package com.jdd.fintech.morse.plugin.strategy;

import com.alibaba.fastjson.JSONObject;
import com.jd.fastjson.JSON;
import com.jdd.fintech.morse.plugin.constans.OpenApiConstans;
import com.jdd.fintech.morse.plugin.ecrypts.SymmetricCrypto;
import com.jdd.fintech.morse.plugin.enums.BizErrorCodeEnum;
import com.jdd.fintech.morse.plugin.enums.BooleanEnum;
import com.jdd.fintech.morse.plugin.plugconfig.MorsePlugValueConfig;
import com.jdd.fintech.morse.plugin.strategy.context.AbstractDataEncryptAndDecryptStrategy;
import com.jdd.fintech.morse.plugin.util.CommonMethodUtils;
import com.jdd.fintech.morse.plugin.util.CryptoUtils;
import com.jdd.fintech.morse.plugin.util.JsonStringUtils;
import com.jdd.fintech.morse.plugin.util.RSAUtil;
import com.jddglobal.filter.support.exception.FilterException;
import com.jddglobal.phevos.gateway.resources.ResourceCapability;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ObjectUtils;

import static com.jdd.fintech.morse.plugin.constans.OpenApiConstans.WD_PRIVATE_KEY;
import static com.jdd.fintech.morse.plugin.constans.OpenApiConstans.WD_PUBLIC_KEY;

/**
 * @description: 金条---通用加解密数据加密策略类
 * @credit: 2021-12-24 11:05
 * @author: fengcheng
 **/
public class JtDataEncryptAndDecryptStrategy extends AbstractDataEncryptAndDecryptStrategy {

    /**
     * 数据加密策略接口方法(金条---通用加解密使用)
     *
     * @param plugValueConfig 插件值对象
     * @param jsonObject      请求对象
     * @param scObj           算法对象
     * @return
     * @throws FilterException 方法
     */
    @Override
    public String dataEncryptsStrategyMethod(MorsePlugValueConfig plugValueConfig, JSONObject jsonObject, SymmetricCrypto scObj) throws FilterException {
        log.info("JtDataEncryptAndDecryptStrategy.dataEncryptsStrategyMethod.金条---通用加密======>开始");
        //是否是对称加解密，非对称是：false；对称是：true
        try {
            //获取请求报文中 业务数据的KEY
            String messageBizDateKey = CommonMethodUtils.getMessageBizDateKey(plugValueConfig);
            if (ObjectUtils.isEmpty(scObj)) {// 非对称式加密
                //开始进行---非对称式加密操作
                return asymmetricEncrypts(plugValueConfig, messageBizDateKey, jsonObject);
            } else {// 对称式加密
                //开始进行---对称式加密操作
                return symmetricEncrypts(plugValueConfig, messageBizDateKey, jsonObject, scObj);
            }
        } catch (Exception e) {
            log.error("JtDataEncryptAndDecryptStrategy.dataEncryptsStrategyMethod.金条---通用加密|加密异常|jsonObject：{} 异常信息：{}", jsonObject.toJSONString(), e.getMessage(), e);
            throw new FilterException(new ResourceCapability.AutoDefineResource(BizErrorCodeEnum.FAILURE_3.getCode(), BizErrorCodeEnum.FAILURE_3.getDesc()));
        }
    }


    /**
     * @方法描述: 非对称式加密
     * @方法名称: JtDataEncryptAndDecryptStrategy.asymmetricEncrypts
     * @方法操作人: ext.fengcheng
     * @方法生成时间: 2022/10/21 16:31
     * @方法执行参数: [plugValueConfig(插件配置值对象), messageBizDateKey(业务对象key), jsonObject(业务数据对象)]
     * @方法返回参数: java.lang.String
     * @方法产生异常:
     **/
    public String asymmetricEncrypts(MorsePlugValueConfig plugValueConfig, String messageBizDateKey, JSONObject jsonObject) throws Exception {
        log.info("JtDataEncryptAndDecryptStrategy.asymmetricEncrypts.非对称式加密=====处理开始");
        //声明密文字符串
        String ciphertext;
        //判断是否完整加解密
        if (BooleanEnum.YES.name().equals(plugValueConfig.getIsComplete().getCode())) {
            ciphertext = RSAUtil.encryptByPublicKey(jsonObject.toJSONString().getBytes(), plugValueConfig.getPublicSecurity());
        } else {
            //获取业务报文数据对象
            String bizMsgObj = jsonObject.getString(messageBizDateKey);
            if (ObjectUtils.isEmpty(bizMsgObj)) {
                return jsonObject.toJSONString();
            }
            ciphertext = RSAUtil.encryptByPublicKey(bizMsgObj.getBytes(), plugValueConfig.getPublicSecurity());
        }
        jsonObject.put(messageBizDateKey, ciphertext);
        log.info("JtDataEncryptAndDecryptStrategy.asymmetricEncrypts.非对称式加密=====处理成功");
        return generateDataSign(plugValueConfig, jsonObject, ciphertext, false);
    }


    /**
     * @方法描述: 对称式加密
     * @方法名称: JtDataEncryptAndDecryptStrategy.symmetricEncrypts
     * @方法操作人: ext.fengcheng
     * @方法生成时间: 2022/10/21 16:31
     * @方法执行参数: [plugValueConfig(插件配置值对象), messageBizDateKey(业务对象key), jsonObject(业务数据对象), scObj(机密算法对象)]
     * @方法返回参数: java.lang.String
     * @方法产生异常:
     **/
    public String symmetricEncrypts(MorsePlugValueConfig plugValueConfig, String messageBizDateKey, JSONObject jsonObject, SymmetricCrypto scObj) throws Exception {
        log.info("JtDataEncryptAndDecryptStrategy.symmetricEncrypts.对称式加密=====处理开始");
        //声明密文字符串
        String ciphertext;
        //判断是否完整加解密
        if (BooleanEnum.YES.name().equals(plugValueConfig.getIsComplete().getCode())) {
            ciphertext = scObj.encryptBase64(jsonObject.toJSONString());
        } else {
            //responseData数据对象
            String responseData = jsonObject.getString(messageBizDateKey);
            if (ObjectUtils.isEmpty(responseData)) {
                return jsonObject.toJSONString();
            }
            ciphertext = scObj.encryptBase64(responseData);
        }
        jsonObject.put(messageBizDateKey, ciphertext);
        log.info("JtDataEncryptAndDecryptStrategy.symmetricEncrypts.对称式加密=====处理结束");
        return generateDataSign(plugValueConfig, jsonObject, ciphertext, true);
    }

    /**
     * @方法描述: 非对称加密成功---开始生成密文签名
     * @方法名称: JtDataEncryptAndDecryptStrategy.generateDataSign
     * @方法操作人: ext.fengcheng
     * @方法生成时间: 2022/10/20 15:51
     * @方法执行参数: [plugValueConfig(插件值对象),
     * jsonObject(请求体),
     * ciphertext(密文),
     * symmetry(是否是非对称加解密)]
     * @方法返回参数: java.lang.String
     * @方法产生异常:
     **/
    public String generateDataSign(MorsePlugValueConfig plugValueConfig, JSONObject jsonObject, String ciphertext, boolean symmetry) throws FilterException {
        log.info("JtDataEncryptAndDecryptStrategy.generateDataSign.加密已经成功=====开始生成签名");
        //声明签名sign
        String sysSign = "";
        try {
            if (symmetry) {
                //对称密文签名
                sysSign = CryptoUtils.sign(ciphertext, plugValueConfig.getSalt());
            } else {
                JSONObject extendParameter = JSONObject.parseObject(plugValueConfig.getExtendParameter());
                String wdPrivateKey = extendParameter.getString(WD_PRIVATE_KEY);
                //非对称密文签名
                sysSign = RSAUtil.sign(ciphertext.getBytes(), wdPrivateKey);
            }
            String signKey = plugValueConfig.getSignKey();
            if (StringUtils.isNotBlank(signKey)) {
                jsonObject.put(signKey, sysSign);
            } else {
                jsonObject.put(OpenApiConstans.SYSSIGN, sysSign);
            }
        } catch (Exception e) {
            log.error("JtDataEncryptAndDecryptStrategy.generateDataSign.加密已经成功.生成签名失败|jsonObject:{}， sysSign：{}|异常信息：{}", jsonObject.toJSONString(), sysSign, e.getMessage(), e);
            throw new FilterException(new ResourceCapability.AutoDefineResource(BizErrorCodeEnum.FAILURE_6.getCode(), BizErrorCodeEnum.FAILURE_6.getDesc()));
        }
        log.info("JtDataEncryptAndDecryptStrategy.generateDataSign.加密已经成功=====生成签名结束");
        log.info("JtDataEncryptAndDecryptStrategy.dataEncryptsStrategyMethod.金条---通用加密======>结束");
        return jsonObject.toJSONString();
    }

    /**
     * 数据解密策略接口方法(金条---通用解密使用)
     *
     * @param plugValueConfig 插件值对象
     * @param jsonObject      请求对象
     * @param scObj           算法对象
     * @return
     * @throws FilterException 方法
     */
    @Override
    public String dataDecryptsStrategyMethod(MorsePlugValueConfig plugValueConfig, JSONObject jsonObject, SymmetricCrypto scObj) throws FilterException {
        log.info("JtDataEncryptAndDecryptStrategy.dataDecryptsStrategyMethod.金条---通用解密======>开始");
        try {
            //获取请求报文中 业务数据的KEY
            String messageBizDateKey = CommonMethodUtils.getMessageBizDateKey(plugValueConfig);
            //密文字符串
            String ciphertext;
            //判断是否完整加解密
            if (BooleanEnum.YES.name().equals(plugValueConfig.getIsComplete().getCode())) {
                ciphertext = jsonObject.toJSONString();
            } else {
                ciphertext = jsonObject.getString(messageBizDateKey);
            }
            String sysSign;
            String signKey = plugValueConfig.getSignKey();
            if (StringUtils.isNotBlank(signKey)) {
                sysSign = jsonObject.getString(signKey);
            } else {
                sysSign = jsonObject.getString(OpenApiConstans.SYSSIGN);
            }
            //解密后的明文
            String plaintext = "";
            // 如果密文不为 null 则需要进行验签和解密
            if (StringUtils.isNotBlank(ciphertext)) {
                if (ObjectUtils.isEmpty(scObj)) {
                    // 非对称式解密
                    plaintext = asymmetricDecryption(plugValueConfig, ciphertext, sysSign);
                } else {
                    // 对称式解密
                    plaintext = symmetricDecryption(plugValueConfig, ciphertext, sysSign, scObj);
                }
            }
            jsonObject.put(messageBizDateKey, plaintext);
        } catch (Exception e) {
            log.error("JtDataEncryptAndDecryptStrategy.dataDecryptsStrategyMethod.金条---通用解密|解密异常|jsonObject：{} 异常信息：{}", jsonObject.toJSONString(), e.getMessage(), e);
            throw new FilterException(new ResourceCapability.AutoDefineResource(BizErrorCodeEnum.FAILURE_4.getCode(), BizErrorCodeEnum.FAILURE_4.getDesc()));
        }
        log.info("JtDataEncryptAndDecryptStrategy.dataDecryptsStrategyMethod.金条---通用解密======>结束");
        return jsonObject.toJSONString();
    }

    /**
     * @方法描述: 非对称式验签解密
     * @方法名称: JtDataEncryptAndDecryptStrategy.asymmetricDecryption
     * @方法操作人: ext.fengcheng
     * @方法生成时间: 2022/10/21 16:05
     * @方法执行参数: [plugValueConfig(插件配置值对象), ciphertext(密文), sysSign(解密sign)]
     * @方法返回参数: java.lang.String
     * @方法产生异常:
     **/
    public String asymmetricDecryption(MorsePlugValueConfig plugValueConfig, String ciphertext, String sysSign) throws Exception {
        log.info("JtDataEncryptAndDecryptStrategy.asymmetricDecryption.非对称式验签解密=====处理开始");
        String plaintext;
        JSONObject extendParameter = JSONObject.parseObject(plugValueConfig.getExtendParameter());
        String wdPublicKey = extendParameter.getString(WD_PUBLIC_KEY);
        boolean isVerifyPass = RSAUtil.verify(ciphertext.getBytes(), wdPublicKey, sysSign);
        if (!isVerifyPass) {
            log.error("JtDataEncryptAndDecryptStrategy.asymmetricDecryption.非对称验签|验签不通过|sysSign:{}, 密文:{}", sysSign, ciphertext);
            throw new FilterException(new ResourceCapability.AutoDefineResource(BizErrorCodeEnum.FAILURE_5.getCode(), BizErrorCodeEnum.FAILURE_5.getDesc()));
        }
        log.info("JtDataEncryptAndDecryptStrategy.asymmetricDecryption.非对称验签成功=====开始解密");
        //判断是否是文件，然后开始进行解密操作
        if (BooleanEnum.YES.getCode().equals(plugValueConfig.getIsFile().getCode())) {
            plaintext = RSAUtil.decryptByPrivateKeyToFile(Base64.decodeBase64(ciphertext), plugValueConfig.getPrivateSecurity());
        } else {
            plaintext = RSAUtil.decryptByPrivateKey(Base64.decodeBase64(ciphertext), plugValueConfig.getPrivateSecurity());
        }
        log.info("JtDataEncryptAndDecryptStrategy.asymmetricDecryption.非对称式验签解密=====处理结束");
        return plaintext;
    }

    /**
     * @方法描述: 对称式验签解密
     * @方法名称: JtDataEncryptAndDecryptStrategy.symmetricDecryption
     * @方法操作人: ext.fengcheng
     * @方法生成时间: 2022/10/21 16:10
     * @方法执行参数: [plugValueConfig(插件配置值对象), ciphertext(密文), sysSign(解密sign), scObj(解密算法对象)]
     * @方法返回参数: java.lang.String
     * @方法产生异常:
     **/
    public String symmetricDecryption(MorsePlugValueConfig plugValueConfig, String ciphertext, String sysSign, SymmetricCrypto scObj) throws Exception {
        String plaintext;
        log.info("JtDataEncryptAndDecryptStrategy.symmetricDecryption.对称式验签解密=====处理开始");
        String salt = plugValueConfig.getSalt();
        boolean isVerifyPass = CryptoUtils.verifySign(salt, ciphertext, sysSign);
        if (!isVerifyPass) {
            log.error("JtDataEncryptAndDecryptStrategy.symmetricDecryption.对称验签|验签|验签不通过|sysSign:{}, 密文:{}", sysSign, ciphertext);
            throw new FilterException(new ResourceCapability.AutoDefineResource(BizErrorCodeEnum.FAILURE_5.getCode(), BizErrorCodeEnum.FAILURE_5.getDesc()));
        }
        log.info("JtDataEncryptAndDecryptStrategy.symmetricDecryption.对称验签成功=====开始解密");
        //判断是否是文件，然后开始进行解密操作
        if (BooleanEnum.YES.getCode().equals(plugValueConfig.getIsFile().getCode())) {
            plaintext = scObj.decryptForFile(ciphertext);
        } else {
            plaintext = scObj.decryptBase64(ciphertext);
        }
        log.info("JtDataEncryptAndDecryptStrategy.symmetricDecryption.对称式验签解密=====处理结束");
        return plaintext;
    }

    /**
     * 构建公共请求对象(金条---通用加解密使用)
     *
     * @param plugValueConfig
     * @param tenantId
     * @param productCode
     * @param jsonObject
     * @return
     */
    @Override
    public String buildCommonRequestObjMethod(MorsePlugValueConfig plugValueConfig, String tenantId, String productCode, JSONObject jsonObject) throws FilterException {
        String interfaceRequestDirection = CommonMethodUtils.getMessageBizDateKey(plugValueConfig);
        log.info("JtDataEncryptAndDecryptStrategy.buildCommonRequestObjMethod.金条---通用加解密---构建响应数据======>开始");
        //判断是否是JSON,如果不是直接返回原始json字符串
        if (!JsonStringUtils.judgeIsJson(interfaceRequestDirection, jsonObject)) {
            return jsonObject.toJSONString();
        }
        try {
            //构建响应数据
            JSONObject jsonRequestData = JSON.parseObject(jsonObject.getString(interfaceRequestDirection).trim(), JSONObject.class);
            jsonRequestData.put("requestNo", jsonObject.getString("requestNo"));
            jsonRequestData.put("txCode", jsonObject.getString("txCode"));
            jsonRequestData.put("version", jsonObject.getString("version"));
            jsonRequestData.put("channelCode", jsonObject.getString("channelCode"));
            jsonRequestData.put("companyId", jsonObject.getString("companyId"));
            jsonRequestData.put("requestTime", jsonObject.getString("requestTime"));
            jsonRequestData.put("productCode", productCode);
            jsonRequestData.put("tenantId", tenantId);
            jsonObject.put(interfaceRequestDirection, jsonRequestData.toJSONString());
            jsonObject.remove(OpenApiConstans.SYSSIGN);
            log.info("JtDataEncryptAndDecryptStrategy.buildCommonRequestObjMethod.金条---通用加解密---构建响应数据======>结束");
            return jsonObject.toJSONString();
        } catch (Exception e) {
            log.error("JtDataEncryptAndDecryptStrategy.dataDecryptsStrategyMethod.金条---通用加解密|数据格式错误，转换失败|解密后的数据|jsonObject:{}|异常信息：{}", jsonObject.toJSONString(), e.getMessage(), e);
            return jsonObject.toJSONString();
        }
    }
}
